#include <brpc/channel.h>
#include <thread>
#include "main.pb.h"
void callback(brpc::Controller *cntl, example::EchoResponse *response)//回调函数，在异步调用时，客户端不会阻塞等待，只有服务端发回消息时，会立刻调用这个函数处理。
{
    std::unique_ptr<brpc::Controller> cntl_guard(cntl);
    std::unique_ptr<example::EchoResponse> response_guard(response);
    if(cntl->Failed())
    {
        std::cout << "rpc调用失败:" <<cntl->ErrorText()<< std::endl;
        return;
    }
    std::cout << "收到响应:" << response->message() << std::endl;
}
int main()
{
    // 构造channel信道链接服务器
    brpc::ChannelOptions options;
    options.connect_timeout_ms = -1; // 设置连接超时时间，-1表示一直等待
    options.timeout_ms = -1;         // 设置rpc请求超时时间，-1表示一直等待
    options.max_retry = 3;           // 设置最大重试次数
    options.protocol = "baidu_std";  // 序列化协议，默认使用baidu_std
    brpc::Channel channel;
    int ret = channel.Init("127.0.0.1:8080", &options);//构建信道，填入需要发送给哪个服务器。channel就是两者之间网络连接的抽象
    if (ret == -1)
    {
        std::cout << "初始化失败" << std::endl;
        return -1;
    }

    // 构造EchoService_Stub对象 ，用于进行rpc调用。可以认为这个对象就是“服务端”在客户端这边的代理/抽象
    example::EchoService_Stub stub(&channel);
    // 构造EchoRequest对象，设置请求参数。也就是要发送给服务端的数据
    example::EchoRequest request;
    request.set_message("hello");
    // 发起请求

    brpc::Controller *cntl = new brpc::Controller();//上下文管理类，目前也就是判断rpc请求是否ok
    example::EchoResponse *response = new example::EchoResponse();
    //cloure其实就是客户端对象。可以用来设置异步回调处理
    google::protobuf::Closure* clusere = google::protobuf::NewCallback(callback, cntl, response);//后面两个arg就是callback的参数
    stub.Echo(cntl, &request, response, clusere);
    // stub.Echo(cntl,&request,response,NULL);//异步才传第四个参数，同步传null  

    // if (cntl->Failed())
    // {
    //     std::cout << "rpc调用失败:" <<cntl->ErrorText()<< std::endl;
    //     return -1;
    // }
    // std::cout << "收到响应:" <<response->message()<< std::endl;

    // 下面两句在异步调用时不能加，因为callback里已经释放了
    //  delete cntl;
    //  delete response;
    std::cout << "异步调用结束" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(3));
    return 0;
}
